﻿// This is an open source non-commercial project. Dear PVS-Studio, please check it.
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com

// ReSharper disable CheckNamespace
// ReSharper disable CommentTypo
// ReSharper disable UnusedMember.Global

/* ThemeBase.cs --
 * Ars Magna project, http://arsmagna.ru
 */

#region Using directives

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Windows.Forms;

#endregion

#nullable enable

namespace AM.Windows.Forms.Docking;

/// <summary>
///
/// </summary>
public abstract class ThemeBase
    : Component
{
    private Color _dockBackColor;
    private bool _showAutoHideContentOnHover;

    /// <summary>
    ///
    /// </summary>
    protected ThemeBase()
    {
        Extender = new DockPanelExtender();
    }

    /// <summary>
    ///
    /// </summary>
    public DockPanelSkin? Skin { get; protected set; }

    /// <summary>
    ///
    /// </summary>
    public DockPanelColorPalette? ColorPalette { get; protected set; }

    /// <summary>
    ///
    /// </summary>
    public IImageService? ImageService { get; protected set; }

    /// <summary>
    ///
    /// </summary>
    public IPaintingService? PaintingService { get; protected set; }

    /// <summary>
    ///
    /// </summary>
    protected ToolStripRenderer ToolStripRenderer { get; set; }

    private Dictionary<ToolStrip, KeyValuePair<ToolStripRenderMode, ToolStripRenderer>> _stripBefore = new ();

    /// <summary>
    ///
    /// </summary>
    /// <param name="toolStrip"></param>
    public void ApplyTo (ToolStrip toolStrip)
    {
        if (toolStrip == null)
        {
            return;
        }

        _stripBefore[toolStrip] =
            new KeyValuePair<ToolStripRenderMode, ToolStripRenderer> (toolStrip.RenderMode, toolStrip.Renderer);
        if (ToolStripRenderer != null)
        {
            toolStrip.Renderer = ToolStripRenderer;
        }

        if (Win32Helper.IsRunningOnMono)
        {
            foreach (var item in toolStrip.Items.OfType<ToolStripDropDownItem>())
            {
                ItemResetOwnerHack (item);
            }
        }
    }

    private void ItemResetOwnerHack (ToolStripDropDownItem item)
    {
        var oldOwner = item.DropDown.OwnerItem;
        item.DropDown.OwnerItem = null;
        item.DropDown.OwnerItem = oldOwner;

        foreach (var child in item.DropDownItems.OfType<ToolStripDropDownItem>())
        {
            ItemResetOwnerHack (child);
        }
    }

    private KeyValuePair<ToolStripManagerRenderMode, ToolStripRenderer> _managerBefore;

    /// <summary>
    ///
    /// </summary>
    public void ApplyToToolStripManager()
    {
        _managerBefore = new KeyValuePair<ToolStripManagerRenderMode, ToolStripRenderer>
            (
                ToolStripManager.RenderMode,
                ToolStripManager.Renderer
            );
    }

    /// <summary>
    ///
    /// </summary>
    public Measures Measures { get; } = new Measures();

    /// <summary>
    ///
    /// </summary>
    public bool ShowAutoHideContentOnHover { get; protected set; } = true;

    /// <summary>
    ///
    /// </summary>
    /// <param name="dockPanel"></param>
    /// <exception cref="InvalidOperationException"></exception>
    public void ApplyTo (DockPanel dockPanel)
    {
        if (Extender.AutoHideStripFactory == null
            || Extender.AutoHideWindowFactory == null
            || Extender.DockIndicatorFactory == null
            || Extender.DockOutlineFactory == null
            || Extender.DockPaneCaptionFactory == null
            || Extender.DockPaneFactory == null
            || Extender.DockPaneSplitterControlFactory == null
            || Extender.DockPaneStripFactory == null
            || Extender.DockWindowFactory == null
            || Extender.FloatWindowFactory == null
            || Extender.PaneIndicatorFactory == null
            || Extender.PanelIndicatorFactory == null
            || Extender.WindowSplitterControlFactory == null)
        {
            throw new InvalidOperationException (Strings.Theme_MissingFactory);
        }

        if (dockPanel.Panes.Count > 0)
        {
            throw new InvalidOperationException (Strings.Theme_PaneNotClosed);
        }

        if (dockPanel.FloatWindows.Count > 0)
        {
            throw new InvalidOperationException (Strings.Theme_FloatWindowNotClosed);
        }

        if (dockPanel.Contents.Count > 0)
        {
            throw new InvalidOperationException (Strings.Theme_DockContentNotClosed);
        }

        if (ColorPalette == null)
        {
            dockPanel.ResetDummy();
        }
        else
        {
            _dockBackColor = dockPanel.DockBackColor;
            dockPanel.DockBackColor = ColorPalette.MainWindowActive.Background;
            dockPanel.SetDummy();
        }

        _showAutoHideContentOnHover = dockPanel.ShowAutoHideContentOnHover;
        dockPanel.ShowAutoHideContentOnHover = ShowAutoHideContentOnHover;
    }

    internal void PostApply (DockPanel dockPanel)
    {
        dockPanel.ResetAutoHideStripControl();
        dockPanel.ResetAutoHideStripWindow();
        dockPanel.ResetDockWindows();
    }

    /// <summary>
    ///
    /// </summary>
    /// <param name="dockPanel"></param>
    public virtual void CleanUp (DockPanel dockPanel)
    {
        if (dockPanel != null)
        {
            if (ColorPalette != null)
            {
                dockPanel.DockBackColor = _dockBackColor;
            }

            dockPanel.ShowAutoHideContentOnHover = _showAutoHideContentOnHover;
        }

        foreach (var item in _stripBefore)
        {
            var strip = item.Key;
            var cache = item.Value;
            if (cache.Key == ToolStripRenderMode.Custom)
            {
                if (cache.Value != null)
                {
                    strip.Renderer = cache.Value;
                }
            }
            else
            {
                strip.RenderMode = cache.Key;
            }
        }

        _stripBefore.Clear();
        if (_managerBefore.Key == ToolStripManagerRenderMode.Custom)
        {
            if (_managerBefore.Value != null)
            {
                ToolStripManager.Renderer = _managerBefore.Value;
            }
        }
        else
        {
            ToolStripManager.RenderMode = _managerBefore.Key;
        }
    }

    /// <summary>
    ///
    /// </summary>
    public DockPanelExtender Extender { get; private set; }

    /// <summary>
    ///
    /// </summary>
    /// <param name="fileToDecompress"></param>
    /// <returns></returns>
    public static byte[] Decompress
        (
            byte[] fileToDecompress
        )
    {
        using (MemoryStream originalFileStream = new MemoryStream (fileToDecompress))
        {
            using (MemoryStream decompressedFileStream = new MemoryStream())
            {
                using (GZipStream decompressionStream =
                       new GZipStream (originalFileStream, CompressionMode.Decompress))
                {
                    //Copy the decompression stream into the output file.
                    byte[] buffer = new byte[4096];
                    int numRead;
                    while ((numRead = decompressionStream.Read (buffer, 0, buffer.Length)) != 0)
                    {
                        decompressedFileStream.Write (buffer, 0, numRead);
                    }

                    return decompressedFileStream.ToArray();
                }
            }
        }
    }
}
